﻿// ===============================================================================
//  Copyright © ymind.net. All rights reserved .
//  官方网站：http://ymind.net/
//  版权所有：彦铭工作室 老陈出品
// ===============================================================================

using System;
using System.Runtime.InteropServices;
using System.Text;
using Lcsoft.TemplateEngine.Core;

namespace Lcsoft.TemplateEngine.XHtmlParser
{
	/// <summary>
	/// 表示 xhtml 标签。
	/// </summary>
	[ComVisible(true)]
	[Serializable]
	public class XHtmlElement : XHtmlNode
	{
		private readonly XHtmlNodeCollection _nodes;
		private bool _terminated;

		/// <summary>
		/// 初始化 <see cref="XHtmlElement"/> 类的新实例。
		/// </summary>
		/// <param name="name"><see cref="XHtmlElement"/> 的名称。</param>
		/// <param name="line"><see cref="XHtmlElement"/> 所在的行数。</param>
		/// <param name="column"><see cref="XHtmlElement"/> 所在的列数。</param>
		public XHtmlElement(string name, int line, int column) : base(line, column)
		{
			if (String.IsNullOrEmpty(name)) throw new ParseException("参数错误", "必须为 XHtmlElement 对象指定合法的 Name 属性，其值不能为 null，也不能为 String.Empty。");

			this._nodes = new XHtmlNodeCollection(this);
			this.Attributes = new XHtmlAttributeCollection(this);
			this.Name = name;
		}

		/// <summary>
		/// 获取 <see cref="XHtmlElement"/> 的名称。
		/// </summary>
		public string Name { get; private set; }

		/// <summary>
		/// 获取 <see cref="XHtmlElement"/> 的子节点的集合。
		/// </summary>
		public XHtmlNodeCollection Nodes
		{
			get
			{
				if (this.IsText) throw new ParseException("操作错误", "XHtmlText 是没有子节点的对象，因此无法操作 XHtmlText.Nodes 属性。");

				return this._nodes;
			}
		}

		/// <summary>
		/// 获取 <see cref="XHtmlElement"/>  的 attribute 属性的集合。
		/// </summary>
		public XHtmlAttributeCollection Attributes { get; private set; }

		/// <summary>
		/// 获取或设置一个值，该值指示当前 <see cref="XHtmlElement"/> 是否是自闭合标记。
		/// </summary>
		protected internal bool IsTerminated
		{
			get { return this.Nodes.Count == 0 && (this._terminated || this.IsExplicitlyTerminated); }
			set { this._terminated = value; }
		}

		/// <summary>
		/// 获取或设置一个值，该值指示当前 <see cref="XHtmlElement"/> 是否需要闭合标记。
		/// </summary>
		protected internal bool IsExplicitlyTerminated { get; set; }

		/// <summary>
		/// 获取 <see cref="XHtmlElement"/> 的文本。
		/// </summary>
		public string Text
		{
			get
			{
				var stringBuilder = new StringBuilder();

				foreach (var node in this._nodes)
				{
					var textNode = node as XHtmlText;

					if (null != textNode) stringBuilder.Append(textNode.Text);
				}

				return stringBuilder.ToString();
			}
		}

		/// <summary>
		/// 获取缩进数量。
		/// </summary>
		public virtual int Indents
		{
			get
			{
				var indents = 0;

				XHtmlNode node = this.Parent;

				while (node != null)
				{
					var element = node as XHtmlElement;

					if (element == null || (element.Name != "html" && element.Name != "body")) break;

					indents++;

					node = node.Parent;
				}

				return indents;
			}
		}

		/// <summary>
		/// 获取缩进空白。
		/// </summary>
		public string IndentBlank
		{
			get { return String.Empty.PadLeft(this.Indents, '\t'); }
		}

		/// <summary>
		/// 返回包含 <see cref="XHtmlElement"/> 内容的 .html 格式的字符串。
		/// </summary>
		/// <returns>返回 <see cref="System.String"/>。</returns>
		public override string ToHtml()
		{
			var html = new StringBuilder();

			html.AppendFormat("<{0}", this.Name);

			foreach (var attribute in this.Attributes.Values) html.AppendFormat(" {0}", attribute.ToHtml());

			if (this._nodes.Count > 0)
			{
				html.Append(">");

				foreach (var node in this._nodes) html.Append(node.ToHtml());

				html.AppendFormat("</{0}>", this.Name);
			}
			else
			{
				if (this.IsExplicitlyTerminated) html.AppendFormat("></{0}>", this.Name);
				else if (this.IsTerminated) html.Append(" />");
				else html.Append(">");
			}

			return html.ToString();
		}

		/// <summary>
		/// 返回包含 <see cref="XHtmlElement"/> 内容的 .aspx 格式的字符串。
		/// </summary>
		/// <returns>返回 <see cref="System.String"/>。</returns>
		public override string ToAspx()
		{
			var aspx = new StringBuilder();

			aspx.AppendFormat("<{0}", this.Name);

			foreach (var attribute in this.Attributes.Values) aspx.AppendFormat(" {0}", attribute.ToHtml());

			if (this._nodes.Count > 0)
			{
				aspx.Append(">");

				foreach (var node in this._nodes) aspx.Append(node.ToAspx());

				aspx.AppendFormat("</{0}>", this.Name);
			}
			else
			{
				if (this.IsExplicitlyTerminated) aspx.AppendFormat("></{0}>", this.Name);
				else if (this.IsTerminated) aspx.Append(" />");
				else aspx.Append(">");
			}

			return aspx.ToString();
		}

		/// <summary>
		/// 返回指定 <see cref="XHtmlAttribute"/> 的值。
		/// </summary>
		/// <param name="attributeName"><see cref="XHtmlAttribute"/> 的名称。</param>
		/// <returns>如果 <see cref="XHtmlElement"/> 包含指定的 <see cref="XHtmlAttribute"/> 则返回其值，否则返回 <see cref="string.Empty"/>。</returns>
		protected string GetAttributeValue(string attributeName) { return this.Attributes.ContainsKey(attributeName) ? (this.Attributes[attributeName].Value ?? String.Empty).Replace("''", "\"").Trim() : String.Empty; }

		/// <summary>
		/// 返回表示 <see cref="XHtmlElement"/> 的字符串。
		/// </summary>
		/// <returns>返回 <see cref="System.String"/>。</returns>
		public override string ToString()
		{
			var html = new StringBuilder();

			html.AppendFormat("<{0}", this.Name);

			foreach (var attribute in this.Attributes.Values) html.AppendFormat(" {0}", attribute);

			html.Append(">");

			return html.ToString();
		}
	}
}
